using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using Konst3d.Efficiency.Suite;

namespace Konst3d.Efficiency.Suite.SparsedBinary
{
    internal interface IMonitoringGroupStorage: IDisposable
    {
        int ID
        {
            get;
        }

        string Title
        {
            get;
            set;
        }

        string Description
        {
            get;
            set;
        }

        DateTime Created
        {
            get;
        }

        ICollection<int> Monitors
        {
            get;
        }

        ICollection<int> Tasks
        {
            get;
        }

        void Delete();
    }

    internal class MonitoringGroup: IMonitoringGroup, IDisposable
    {
        #region Constructor

        public MonitoringGroup(IMonitoringGroupStorage storage, MonitorCollectionStorage monitorCollection, TaskStorage taskCollection)
        {
            Contract.Requires(storage != null);

            _storage = storage;
            _monitorStorage = monitorCollection;
            _taskStorage = taskCollection;

            foreach (int id in _storage.Monitors)
            {
                _monitors.Add(_monitorStorage[id]);
            }

            _monitors.ItemAdded += OnMonitorAdded;
            _monitors.ItemRemoved += OnMonitorRemoved;

            foreach (int id in _storage.Tasks)
            {
                _tasks.Add(_taskStorage[id]);
            }

            _tasks.ItemAdded += OnTaskAdded;
            _tasks.ItemRemoved += OnTaskRemoved;

            _monitorStorage.MonitorRemoved += OnMonitorDeleted;
            _taskStorage.TaskRemoved += OnTaskDeleted;
        }

        #endregion // Constructor

        #region IMonitoringGroup Members

        public event MonitoringGroupChangedHandler Changed;

        public int ID
        {
            get
            {
                return _storage.ID;
            }
        }

        public string Title
        {
            get
            {
                return _storage.Title;
            }
            set
            {
                _storage.Title = value;
            }
        }

        public string Description
        {
            get
            {
                return _storage.Description;
            }
            set
            {
                _storage.Description = value;
            }
        }

        public IIdentifiableCollection<IMonitor, int> Monitors
        {
            get
            {
                return _monitors;
            }
        }

        public IIdentifiableCollection<ITask, int> Tasks
        {
            get
            {
                return _tasks;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _monitors.ItemAdded -= OnMonitorAdded;
                    _monitors.ItemRemoved -= OnMonitorRemoved;
                    _monitors.Clear();
                    _monitors = null;

                    _tasks.ItemAdded -= OnTaskAdded;
                    _tasks.ItemRemoved -= OnTaskRemoved;
                    _tasks.Clear();
                    _tasks = null;

                    _monitorStorage.MonitorRemoved -= OnMonitorDeleted;
                    _taskStorage.TaskRemoved -= OnTaskDeleted;

                    _storage.Dispose();
                    _storage = null;
                }

                _disposed = true;
            }
        }

        #endregion

        #region Public Methods

        public void Delete()
        {
            Contract.Assert(!_disposed);

            _storage.Delete();

            Dispose();
        }

        #endregion // Public Methods

        #region Event Handlers

        private void OnMonitorAdded(IMonitor monitor)
        {
            _storage.Monitors.Add(monitor.ID);
        }

        private void OnMonitorRemoved(IMonitor monitor)
        {
            _storage.Monitors.Remove(monitor.ID);
        }

        private void OnTaskAdded(ITask task)
        {
            _storage.Tasks.Add(task.ID);
        }

        private void OnTaskRemoved(ITask task)
        {
            _storage.Tasks.Remove(task.ID);
        }

        private void OnMonitorDeleted(MonitorCollectionStorage sender, int id)
        {
            if (_monitors.Contains(id))
            {
                _monitors.Remove(id);

                if (Changed != null)
                {
                    Changed(this, MonitoringGroupChangeKind.MonitorDeleted);
                }
            }
        }

        private void OnTaskDeleted(TaskStorage sender, int id)
        {
            if (_tasks.Contains(id))
            {
                _tasks.Remove(id);

                if (Changed != null)
                {
                    Changed(this, MonitoringGroupChangeKind.TaskDeleted);
                }
            }
        }

        #endregion // Event Handlers

        #region Fields

        private bool _disposed = false;
        private IMonitoringGroupStorage _storage;
        private MonitorCollectionStorage _monitorStorage;
        private TaskStorage _taskStorage;
        private ObservableIdentifiableCollection<IMonitor, int> _monitors = new ObservableIdentifiableCollection<IMonitor, int>();
        private ObservableIdentifiableCollection<ITask, int> _tasks = new ObservableIdentifiableCollection<ITask, int>();

        #endregion // Fields
    }
}
